package com.ffcc.fitness.gym.service.impl;

import com.ffcc.fitness.base.exception.ServiceException;
import com.ffcc.fitness.base.response.StatusCode;
import com.ffcc.fitness.common.service.VerificationService;
import com.ffcc.fitness.gym.mapper.GymMapper;
import com.ffcc.fitness.gym.pojo.dto.GymClaimParam;
import com.ffcc.fitness.gym.pojo.dto.GymSaveParam;
import com.ffcc.fitness.gym.pojo.dto.POIGymParam;
import com.ffcc.fitness.gym.pojo.entity.Gym;
import com.ffcc.fitness.gym.pojo.vo.GymInfo;
import com.ffcc.fitness.gym.service.GymService;
import com.ffcc.fitness.user.mapper.UserMapper;
import com.ffcc.fitness.user.pojo.vo.UserVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class GymServiceImpl implements GymService {
    @Autowired
    GymMapper gymMapper;

    @Autowired
    UserMapper userMapper;

    @Autowired
    private VerificationService verificationService;

    @Override
    public void insert(GymSaveParam gymSaveParam) {
        log.info("创建场馆开始，参数: {}", gymSaveParam);

        Gym gym = new Gym();
        BeanUtils.copyProperties(gymSaveParam, gym);

        // 设置默认状态为未认领
        if (gym.getStatus() == null) {
            gym.setStatus("unclaimed");
        }

        gym.setCreateTime(LocalDateTime.now());
        gymMapper.insert(gym);

        log.info("创建场馆成功，gymId: {}", gym.getGymId());
    }

    @Override
    public GymInfo getGymByUserId(Long userId) {
        log.info("根据用户ID查询场馆信息, userId: {}", userId);
        Gym gym = gymMapper.selectByUserId(userId);

        if (gym == null) {
            log.info("未找到该用户关联的场馆");
            return null;
        }

        return new GymInfo(gym);
    }

    @Override
    public GymInfo getClaimedGymByUserId(Long userId) {
        log.info("根据用户ID查询已认领的场馆信息, userId: {}", userId);

        if (userId == null) {
            log.warn("userId参数为null");
            return null;
        }

        Gym gym = gymMapper.selectClaimedByUserId(userId);
        log.info("数据库查询结果: {}", gym);

        if (gym == null) {
            log.info("未找到该用户认领的场馆");
            return null;
        }

        log.info("找到场馆: gymId={}, name={}, status={}, userId={}",
                gym.getGymId(), gym.getName(), gym.getStatus(), gym.getUserId());

        GymInfo gymInfo = new GymInfo(gym);

        // 获取认领员工信息
        if (gym.getUserId() != null) {
            try {
                UserVO claimedStaff = userMapper.selectByUserId(gym.getUserId());
                if (claimedStaff != null) {
                    gymInfo.setClaimedStaff(claimedStaff);
                    log.info("已设置认领员工信息: {}", claimedStaff.getUsername());
                }
            } catch (Exception e) {
                log.error("获取认领员工信息失败, userId: {}", gym.getUserId(), e);
            }
        }

        log.info("返回场馆信息: {}", gymInfo);
        return gymInfo;
    }

    @Override
    public GymInfo selectByUsername(String username) {
        log.info("根据用户名查询场馆信息, username: {}", username);
        Gym gym = gymMapper.selectByUsername(username);

        if (gym == null) {
            log.info("未找到该用户名关联的场馆");
            return null;
        }

        return new GymInfo(gym);
    }

    @Override
    public void updateGym(Gym gym) {
        log.info("更新场馆信息, gymId: {}", gym.getGymId());

        // 检查场馆是否存在
        Gym existingGym = gymMapper.selectById(gym.getGymId());
        if (existingGym == null) {
            throw new ServiceException(StatusCode.GYM_NOT_FOUND);
        }

        gymMapper.update(gym);
        log.info("场馆信息更新成功");
    }

    @Override
    @Transactional
    public void claimGym(GymClaimParam gymClaimParam) {
        log.info("认领场馆开始，参数: {}", gymClaimParam);

        // 检查场馆是否存在，支持gym_id或poi_id查询
        String gymIdOrPoiId = gymClaimParam.getGymId();
        Gym gym = null;

        // 首先尝试用POI ID查询
        gym = gymMapper.selectByPoiId(gymIdOrPoiId);

        // 如果POI ID查询失败，尝试用gym_id查询
        if (gym == null) {
            try {
                Long gymId = Long.parseLong(gymIdOrPoiId);
                gym = gymMapper.selectById(gymId);
            } catch (NumberFormatException e) {
                log.info("gymId不是数字格式，仅尝试POI ID查询: {}", gymIdOrPoiId);
            }
        }

        if (gym == null) {
            log.error("场馆不存在, gymId/poiId: {}", gymIdOrPoiId);
            throw new ServiceException(StatusCode.GYM_NOT_FOUND);
        }

        // 检查场馆是否已被认领
        if (gym.getUserId() != null && !"unclaimed".equals(gym.getStatus())) {
            throw new ServiceException(StatusCode.GYM_ALREADY_CLAIMED);
        }

        // 检查用户是否存在且是否为场馆人员角色
        UserVO user = userMapper.selectByUserId(gymClaimParam.getUserId());
        if (user == null) {
            throw new ServiceException(StatusCode.DATA_UNEXISTS);
        }

        if (user.getRole() != 4) {
            throw new ServiceException(StatusCode.NO_PERMISSION);
        }
        // 验证邮箱验证码
        String email = gymClaimParam.getEmail();
        String code = gymClaimParam.getVerificationCode();

        if (email != null && code != null) {
            // 使用新的验证服务
            boolean isValid = verificationService.verifyEmailCode(email, code);
            if (!isValid) {
                throw new ServiceException(StatusCode.VERIFICATION_CODE_ERROR);
            }
        }
        // 更新场馆信息，绑定用户ID
        gym.setUserId(gymClaimParam.getUserId());
        gym.setStatus("closed");
        gym.setClaimedAt(LocalDateTime.now());

        // 更新场馆认领信息
        if (gymClaimParam.getClaimantName() != null) {
            gym.setName(gymClaimParam.getClaimantName());
        }

        if (gymClaimParam.getClaimDescription() != null) {
            gym.setDescription(gymClaimParam.getClaimDescription());
        }

        gymMapper.update(gym);
        log.info("认领场馆成功，gymId: {}, userId: {}", gym.getGymId(), gym.getUserId());
    }

    @Override
    public boolean isClaimable(String gymIdOrPoiId) {
        log.info("检查场馆是否可认领, gymId/poiId: {}", gymIdOrPoiId);

        Gym gym = null;

        // 首先尝试作为POI ID查询
        gym = gymMapper.selectByPoiId(gymIdOrPoiId);

        // 如果POI ID查询失败，尝试作为数字型gym_id查询
        if (gym == null) {
            try {
                Long gymId = Long.parseLong(gymIdOrPoiId);
                gym = gymMapper.selectById(gymId);
            } catch (NumberFormatException e) {
                log.info("gymId不是数字格式，仅尝试POI ID查询: {}", gymIdOrPoiId);
            }
        }

        if (gym == null) {
            log.info("场馆不存在，不可认领");
            return false;
        }

        // 场馆未被认领则可以认领
        boolean claimable = gym.getUserId() == null || "unclaimed".equals(gym.getStatus());
        log.info("场馆 {} 是否可认领: {}", gymIdOrPoiId, claimable);

        return claimable;
    }

    @Override
    public boolean sendVerificationCode(String email) {
        log.info("发送验证码到邮箱: {}", email);
        try {
            return verificationService.sendEmailVerificationCode(email);
        } catch (Exception e) {
            log.error("发送验证码失败", e);
            return false;
        }
    }

    @Override
    public boolean verifyEmailCode(String email, String code) {
        log.info("验证邮箱验证码: email={}, code={}", email, code);
        try {
            return verificationService.verifyEmailCode(email, code);
        } catch (Exception e) {
            log.error("验证邮箱验证码失败", e);
            return false;
        }
    }

    @Override
    public String getUserEmail(Long userId) {
        log.info("获取用户邮箱, userId: {}", userId);

        UserVO user = userMapper.selectByUserId(userId);
        if (user == null) {
            log.info("用户不存在");
            return null;
        }
        return user.getEmail();
    }

    @Override
    public int savePOIGyms(List<POIGymParam> poiGyms) {
        log.info("批量存储POI场馆数据，数量: {}", poiGyms.size());

        if (poiGyms == null || poiGyms.isEmpty()) {
            return 0;
        }

        List<Gym> gymsToInsert = new ArrayList<>();

        for (POIGymParam poiGym : poiGyms) {
            // 检查是否已存在相同POI ID的场馆
            if (poiGym.getId() != null) {
                Gym existingGym = gymMapper.selectByPoiId(poiGym.getId());
                if (existingGym != null) {
                    log.info("POI场馆已存在，跳过: {}", poiGym.getName());
                    continue;
                }
            }

            // 转换为Gym实体
            Gym gym = new Gym();
            gym.setName(poiGym.getName());
            gym.setArea(poiGym.getArea() != null ? poiGym.getArea() : poiGym.getAdname());
            gym.setType(determineGymType(poiGym.getType()));
            gym.setPhone(poiGym.getPhone() != null ? poiGym.getPhone() : poiGym.getTel());
            gym.setAddress(poiGym.getAddress());
            gym.setOpeningHours(poiGym.getOpeningHours() != null ? poiGym.getOpeningHours() : poiGym.getBusinessHours());
            gym.setDescription(poiGym.getDescription());
            //默认为未认领状态
            gym.setStatus("unclaimed");
            gym.setPoiId(poiGym.getId());
            gym.setIsPoiSource(true);
            gym.setCreateTime(LocalDateTime.now());

            // 处理POI的photos字段，转换为images字符串
            if (poiGym.getPhotos() != null && !poiGym.getPhotos().isEmpty()) {
                List<String> imageUrls = poiGym.getPhotos().stream()
                        .map(POIGymParam.PhotoInfo::getUrl)
                        .filter(url -> url != null && !url.trim().isEmpty())
                        .collect(Collectors.toList());

                if (!imageUrls.isEmpty()) {
                    // 将图片URL数组转换为逗号分隔的字符串存储
                    gym.setImages(String.join(",", imageUrls));
                }
            }

            gymsToInsert.add(gym);
        }

        if (gymsToInsert.isEmpty()) {
            log.info("没有新的POI场馆需要插入");
            return 0;
        }

        int result = gymMapper.batchInsertPOI(gymsToInsert);
        log.info("成功存储POI场馆数据，数量: {}", result);

        return result;
    }

    @Override
    public List<GymInfo> getUnclaimedPOIGyms() {
        log.info("获取未认领的POI场馆列表");

        List<Gym> gyms = gymMapper.selectUnclaimedPOIGyms();
        return gyms.stream()
                .map(GymInfo::new)
                .collect(Collectors.toList());
    }

    @Override
    public List<GymInfo> getAllPOIGyms() {
        log.info("获取所有POI场馆列表");

        List<Gym> gyms = gymMapper.selectAllPOIGyms();
        List<GymInfo> gymInfos = gyms.stream()
                .map(GymInfo::new)
                .collect(Collectors.toList());

        // 已认领的场馆填充场馆管理人员信息
        for (GymInfo gymInfo : gymInfos) {
            if (gymInfo.getUserId() != null && !"unclaimed".equals(gymInfo.getStatus())) {
                try {
                    UserVO claimedStaff = userMapper.selectByUserId(gymInfo.getUserId());
                    if (claimedStaff != null) {
                        gymInfo.setClaimedStaff(claimedStaff);
                        log.debug("已设置认领员工信息: {}", claimedStaff.getUsername());
                    }
                } catch (Exception e) {
                    log.error("获取认领员工信息失败, userId: {}", gymInfo.getUserId(), e);
                }
            }
        }

        return gymInfos;
    }

    @Override
    public List<GymInfo> getGymsByArea(String area) {
        log.info("根据区域获取场馆列表, area: {}", area);

        List<Gym> gyms = gymMapper.selectByArea(area);
        return gyms.stream()
                .map(GymInfo::new)
                .collect(Collectors.toList());
    }

    @Override
    public List<GymInfo> getNearbyGyms(Double centerLng, Double centerLat, Double radius) {
        log.info("获取附近场馆, 中心坐标: [{}, {}], 半径: {}km", centerLng, centerLat, radius);

        // 计算搜索范围的经纬度边界（简单算法，1度约等于111公里）
        double degreeRadius = radius / 111.0;
        double minLng = centerLng - degreeRadius;
        double maxLng = centerLng + degreeRadius;
        double minLat = centerLat - degreeRadius;
        double maxLat = centerLat + degreeRadius;

        List<Gym> gyms = gymMapper.selectNearbyGyms(minLng, maxLng, minLat, maxLat);
        return gyms.stream()
                .map(GymInfo::new)
                .collect(Collectors.toList());
    }

    /**
     * 根据POI类型确定标准化的场馆类型
     */
    private String determineGymType(String poiType) {
        if (poiType == null) {
            return "健身房";
        }

        String lowerType = poiType.toLowerCase();

        if (lowerType.contains("健身") || lowerType.contains("gym")) {
            return "健身房";
        } else if (lowerType.contains("瑜伽") || lowerType.contains("yoga")) {
            return "瑜伽馆";
        } else if (lowerType.contains("游泳") || lowerType.contains("swim")) {
            return "游泳馆";
        } else if (lowerType.contains("拳击") || lowerType.contains("boxing")) {
            return "拳击馆";
        } else if (lowerType.contains("私教") || lowerType.contains("personal")) {
            return "私教工作室";
        } else if (lowerType.contains("羽毛球") || lowerType.contains("badminton")) {
            return "羽毛球馆";
        } else if (lowerType.contains("篮球") || lowerType.contains("basketball")) {
            return "篮球馆";
        } else if (lowerType.contains("网球") || lowerType.contains("tennis")) {
            return "网球馆";
        } else if (lowerType.contains("乒乓球") || lowerType.contains("ping pong")) {
            return "乒乓球馆";
        } else if (lowerType.contains("舞蹈") || lowerType.contains("dance")) {
            return "舞蹈室";
        } else {
            return "健身房"; // 默认类型
        }
    }

    @Override
    public void updateGymStatus(Long gymId, Long userId, String status) {
        log.info("更新场馆状态，gymId: {}, userId: {}, status: {}", gymId, userId, status);

        // 验证场馆是否存在
        Gym gym = gymMapper.selectById(gymId);
        if (gym == null) {
            throw new ServiceException(StatusCode.GYM_NOT_FOUND);
        }
        // 验证用户是否是场馆拥有者
        if (!userId.equals(gym.getUserId())) {
            throw new ServiceException(StatusCode.NO_PERMISSION);
        }

        // 更新状态
        gym.setStatus(status);
        gym.setUpdateTime(LocalDateTime.now());

        int result = gymMapper.update(gym);
        if (result <= 0) {
            throw new ServiceException(StatusCode.OPERATION_FAILED);
        }

        log.info("场馆状态更新成功，gymId: {}, newStatus: {}", gymId, status);
    }
}
